package com.xxx.auth.common.web.exception.handler;

import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
import com.xxx.auth.common.web.dto.ResultDTO;
import com.xxx.auth.common.web.exception.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.nio.file.AccessDeniedException;

@RestControllerAdvice
@Slf4j
public class CommonExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResultDTO handleConstraintViolationException(Exception ex) {

        if (ex instanceof MethodArgumentNotValidException methodArgumentNotValidException) {
            log.warn("", ex);

            String message = methodArgumentNotValidException.getFieldErrors().toString();
            return ResultDTO.error("400", message);
        } else if (ex instanceof DataConflictValidationException) {
            log.warn("", ex);

            if (StringUtils.isNotBlank(ex.getMessage())) {
                return ResultDTO.error("409", "Data Conflict Exception: " + ex.getMessage());
            }
            return ResultDTO.error("409", "Data Conflict Exception");
        } else if (ex instanceof DataNotFoundException) {
            log.warn("", ex);

            if (StringUtils.isNotBlank(ex.getMessage())) {
                return ResultDTO.error("404", "Data Not Found Exception: " + ex.getMessage());
            }
            return ResultDTO.error("404", "Data Not Found Exception");
        } else if (ex instanceof PermissionException || ex instanceof AccessDeniedException) {
            log.warn("", ex);

            return ResultDTO.error("403", "Permission Exception");
        } else if (ex instanceof MethodArgumentTypeMismatchException
                || ex.getCause() instanceof UnrecognizedPropertyException
                || ex.getCause() instanceof InvalidFormatException
                || ex.getCause() instanceof HttpMessageNotReadableException
                || ex instanceof ArgumentException) {
            log.warn("", ex);

            return ResultDTO.error("400", ex.getMessage());
        } else if (ex.getCause() instanceof HttpRequestMethodNotSupportedException) {
            log.warn("", ex);

            return ResultDTO.error("405", ex.getMessage());
        } else if (ex instanceof UnprocessableEntityException) {
            log.warn("", ex);
            return ResultDTO.error("422", ex.getMessage());
        }

        log.error("", ex);
        return ResultDTO.error("500", ex.getMessage());
    }
}
